// 后端交互相关

import childProcess from 'child_process';
import readline from 'readline';

import { sendNotification } from './jsonrpc.mjs';
import settings from './settings.mjs';

const BACKEND_STOP_TIMEOUT = 10 * 1000;

let backendProcess = null;
let backendReadLineInterface = null;
const registeredLineHandlers = [];

/**
 * 获取后端进程运行状况。
 *
 * @returns {boolean}
 */
function isBackendRunning() {
  return backendProcess !== null;
}

/**
 * 启动后端进程。
 *
 * @returns {void}
 */
function startBackend() {
  if (isBackendRunning()) {
    console.warn('后端进程正在运行，如需重新启动则需先停止。');
    return;
  }

  const { command, args } = settings.get('backend').value();
  const process = childProcess.spawn(command, args);
  const rl = readline.createInterface({ input: process.stdout });

  rl.on('line', (line) => {
    registeredLineHandlers.forEach((handler) => {
      handler(line);
    });
  });
  rl.on('close', () => {
    backendReadLineInterface = null;
  });

  process.on('exit', () => {
    backendProcess = null;
    if (backendReadLineInterface !== null) {
      backendReadLineInterface = null;
    }
  });

  backendReadLineInterface = rl;
  backendProcess = process;
}

/**
 * 停止后端进程。
 *
 * @param {boolean} force 是否强制关闭
 * @returns {void}
 */
function stopBackend(force = false) {
  if (!isBackendRunning()) {
    console.warn('后端进程已经停止。');
    return;
  }

  if (force) {
    backendProcess.kill();
  } else {
    sendNotification('exit');
    setTimeout(() => {
      console.debug('后端进程未及时停止；将强制关闭。');
      stopBackend(true);
    }, BACKEND_STOP_TIMEOUT);
  }
}

/**
 * 向后端发送一行字符串。
 *
 * @param {string} line 发送的字符串
 * @returns {void}
 */
function sendLine(line) {
  if (!isBackendRunning()) {
    console.warn('后端进程不在运行；正在启动后端进程...');
    startBackend();
  }

  backendProcess.stdin.write(`${line}\n`);
}

/**
 * 注册后端输出行回调函数。
 * 对于后端输出的每一行，都将调用一次该函数。
 *
 * @param {(line: string) => any} handler 回调函数
 * @returns {void}
 */
function registerLineHandler(handler) {
  if (!registeredLineHandlers.includes(handler)) {
    registeredLineHandlers.push(handler);
  }
}

/**
 * 移除注册的后端输出行回调函数。
 *
 * @param {(line: string) => any} handler 回调函数
 */
function removeLineHandler(handler) {
  const index = registeredLineHandlers.indexOf(handler);
  if (index !== -1) {
    registeredLineHandlers.splice(index, 1);
  }
}

registerLineHandler((line) => {
  const trimmedLine = line.trim();
  if (trimmedLine && trimmedLine.charAt(0) === '{') {
    console.debug(line);
  } else {
    console.log(line);
  }
});

export {
  isBackendRunning,
  startBackend,
  stopBackend,
  sendLine,
  registerLineHandler,
  removeLineHandler,
};
